﻿using HardcoreGame.Common.Abstract;
using HardcoreGame.Common.Configs;
using HardcoreGame.Common.Cores.Data;
using HardcoreGame.Common.Cores.Seasons;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using Terraria;
using Terraria.GameContent;
using Terraria.ModLoader;
using Terraria.UI;

namespace HardcoreGame.Common.Systems
{
    public class TemperatureSystem : ModSystem
    {
        private static float displayedTemperature = 20f;
        private static float targetTemperature = 20f;
        public float CurrentTemperature { get; private set; }
        public TemperatureData temperatureData;
        public override void OnWorldLoad()
        {
            temperatureData = new TemperatureData
            {
                DayTemperature = 25f,
                NightTemperature = 10f
            };
        }

        public override void PreUpdateWorld()
        {
            Player player = Main.LocalPlayer;
            float currentTemperature = 0;
            SeasonSystem seasonSystem = ModContent.GetInstance<SeasonSystem>();
            Season currentSeason = seasonSystem.currentSeason;
            var currentDay = seasonSystem.dayCounter;

            if (currentSeason is Spring)
            {
                if (player.ZoneForest)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 7f : temperatureData.NightTemperature;
                else if (player.ZoneDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 5f : temperatureData.NightTemperature - 2f;
                else if (player.ZoneCorrupt)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 10f;
                else if (player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 17f : temperatureData.NightTemperature - 2f;
                else if (player.ZoneUndergroundDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 3f;
                else if (player.ZoneCorrupt && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 20f : temperatureData.NightTemperature - 18f;
                else if (player.ZoneNormalCaverns)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 5f;
                else if (player.ZoneBeach)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 3f : temperatureData.NightTemperature;
                else if (player.ZoneCrimson)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 10f;
                else if (player.ZoneUnderworldHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 75f : temperatureData.NightTemperature + 90f;
                else if (player.ZoneJungle)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature : temperatureData.NightTemperature + 3f;
                else if (player.ZoneNormalSpace)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 248.15f : temperatureData.NightTemperature - 263.15f;
                else if (player.ZoneJungle && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneHallow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature : temperatureData.NightTemperature;
                else if (player.ZoneSnow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 25f : temperatureData.NightTemperature - 25f;
                else if (player.ZoneLihzhardTemple)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 18f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneHallow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 5f;
                else if (player.ZoneSnow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 35f : temperatureData.NightTemperature - 25f;
                else if (player.ZoneGlowshroom)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 18f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneDungeon)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 13f : temperatureData.NightTemperature - 6f;
                else if (player.ZoneSkyHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 5f : temperatureData.NightTemperature - 3f;
                else
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature : temperatureData.NightTemperature;
            }
            else if (currentSeason is Summer)
            {
                if (player.ZoneForest)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 5f + 7f : temperatureData.NightTemperature + 3f + 2f;
                else if (player.ZoneDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 20f + 7f : temperatureData.NightTemperature + 15f + 2f;
                else if (player.ZoneCorrupt)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 5f;
                else if (player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneUndergroundDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 5f : temperatureData.NightTemperature + 2f;
                else if (player.ZoneCorrupt && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 18f : temperatureData.NightTemperature - 12f;
                else if (player.ZoneNormalCaverns)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneBeach)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 8f : temperatureData.NightTemperature + 6f;
                else if (player.ZoneCrimson)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 5f;
                else if (player.ZoneUnderworldHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 75f : temperatureData.NightTemperature + 90f;
                else if (player.ZoneJungle)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 8f : temperatureData.NightTemperature + 10f;
                else if (player.ZoneNormalSpace)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 248.15f : temperatureData.NightTemperature - 263.15f;
                else if (player.ZoneJungle && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 8f : temperatureData.NightTemperature + 1f;
                else if (player.ZoneHallow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 3f : temperatureData.NightTemperature + 2f;
                else if (player.ZoneSnow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 15f;
                else if (player.ZoneLihzhardTemple)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneHallow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 8f : temperatureData.NightTemperature - 3f;
                else if (player.ZoneSnow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 25f : temperatureData.NightTemperature - 15f;
                else if (player.ZoneGlowshroom)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneDungeon)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 3f;
                else if (player.ZoneSkyHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 3f : temperatureData.NightTemperature - 1f;
                else
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature : temperatureData.NightTemperature;
            }
            else if (currentSeason is Autumn)
            {
                if (player.ZoneForest)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 2f : temperatureData.NightTemperature - 5f;
                else if (player.ZoneDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 10f : temperatureData.NightTemperature + 5f;
                else if (player.ZoneCorrupt)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 8f;
                else if (player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 13f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneUndergroundDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 8f : temperatureData.NightTemperature + 1f;
                else if (player.ZoneCorrupt && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 16f : temperatureData.NightTemperature - 10f;
                else if (player.ZoneNormalCaverns)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 2f;
                else if (player.ZoneBeach)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 2f : temperatureData.NightTemperature + 3f;
                else if (player.ZoneCrimson)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 8f;
                else if (player.ZoneUnderworldHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 75f : temperatureData.NightTemperature + 90f;
                else if (player.ZoneJungle)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 3f : temperatureData.NightTemperature + 5f;
                else if (player.ZoneNormalSpace)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 248.15f : temperatureData.NightTemperature - 263.15f;
                else if (player.ZoneJungle && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 6f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneHallow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 1f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneSnow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 20f : temperatureData.NightTemperature - 20f;
                else if (player.ZoneLihzhardTemple)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 16f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneHallow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 6f : temperatureData.NightTemperature - 3f;
                else if (player.ZoneSnow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 30f : temperatureData.NightTemperature - 20f;
                else if (player.ZoneGlowshroom)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 16f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneDungeon)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 11f : temperatureData.NightTemperature - 4f;
                else if (player.ZoneSkyHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 4f : temperatureData.NightTemperature - 2f;
                else
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature : temperatureData.NightTemperature;
            }
            else if (currentSeason is Winter)
            {
                if (player.ZoneForest)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 18f : temperatureData.NightTemperature - 25f;
                else if (player.ZoneDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 5f : temperatureData.NightTemperature - 10f;
                else if (player.ZoneCorrupt)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 20f : temperatureData.NightTemperature - 15f;
                else if (player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneUndergroundDesert)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 2f;
                else if (player.ZoneCorrupt && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 22f : temperatureData.NightTemperature - 16f;
                else if (player.ZoneNormalCaverns)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 8f : temperatureData.NightTemperature - 2f;
                else if (player.ZoneBeach)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 12f;
                else if (player.ZoneCrimson)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 20f : temperatureData.NightTemperature - 15f;
                else if (player.ZoneUnderworldHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature + 75f : temperatureData.NightTemperature + 90f;
                else if (player.ZoneJungle)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 5f : temperatureData.NightTemperature - 8f;
                else if (player.ZoneNormalSpace)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 248.15f : temperatureData.NightTemperature - 263.15f;
                else if (player.ZoneJungle && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 3f;
                else if (player.ZoneHallow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 5f : temperatureData.NightTemperature - 8f;
                else if (player.ZoneSnow)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 35f : temperatureData.NightTemperature - 35f;
                else if (player.ZoneLihzhardTemple)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 20f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneHallow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 12f : temperatureData.NightTemperature - 6f;
                else if (player.ZoneSnow && player.ZoneNormalUnderground)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 40f : temperatureData.NightTemperature - 30f;
                else if (player.ZoneGlowshroom)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 20f : temperatureData.NightTemperature - 1f;
                else if (player.ZoneDungeon)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 15f : temperatureData.NightTemperature - 7f;
                else if (player.ZoneSkyHeight)
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature - 10f : temperatureData.NightTemperature - 8f;
                else
                    currentTemperature = Main.dayTime ? temperatureData.DayTemperature : temperatureData.NightTemperature;
            }
            CurrentTemperature = currentTemperature;
        }
        public override void ModifyInterfaceLayers(List<GameInterfaceLayer> layers)
        {
            int temperatureLayerIndex = layers.FindIndex(layer => layer.Name.Equals("Vanilla: Inventory"));
            if (temperatureLayerIndex != -1)
            {
                layers.Insert(temperatureLayerIndex, new LegacyGameInterfaceLayer(
                    "HardcoreGame: TemperatureUI",
                    delegate
                    {
                        DrawTemperature(Main.spriteBatch);
                        return true;
                    },
                    InterfaceScaleType.UI));
            }
        }
        public static void DrawTemperature(SpriteBatch spriteBatch)
        {
            if (Main.LocalPlayer == null) return;
            targetTemperature = ModContent.GetInstance<TemperatureSystem>().CurrentTemperature;
            UpdateTemperatureAnimation();

            try
            {
                const float scaleMultiplier = 0.7f;
                const int offsetX = 340;
                const int offsetY = 50;

                int width = (int)(32 * scaleMultiplier);
                int height = (int)(128 * scaleMultiplier);
                Vector2 thermometerPosition = new(Main.screenWidth - width - offsetX, offsetY + Main.screenHeight * 0.1f);
                float celsiusTemperature = displayedTemperature;
                (float tempValue, string unit) = ConvertTemperature(celsiusTemperature);
                float fillRatio = CalculateFillRatio(tempValue, unit);
                spriteBatch.Draw(ModContent.Request<Texture2D>("HardcoreGame/Assets/Textures/Temperature/TempBack").Value, thermometerPosition, null, Color.White, 0f, Vector2.Zero, scaleMultiplier, SpriteEffects.None, 0f);
                DrawThermometerFill(spriteBatch, ModContent.Request<Texture2D>("HardcoreGame/Assets/Textures/Temperature/TempFront").Value, thermometerPosition, fillRatio, scaleMultiplier, width, height);
                DrawTemperatureText(spriteBatch, tempValue, unit, thermometerPosition, width, height);
            }
            catch (Exception ex)
            {
                ModContent.GetInstance<HardcoreGame>().Logger.Error("温度计绘制错误: " + ex.Message);
            }
        }

        private static void UpdateTemperatureAnimation()
        {
            float difference = targetTemperature - displayedTemperature;
            if (Math.Abs(difference) < 0.1f)
            {
                displayedTemperature = targetTemperature;
                return;
            }
            float currentSpeed = 1 * (5f + Math.Abs(difference) * 0.1f);
            displayedTemperature += Math.Sign(difference) * Math.Min(currentSpeed * (1f / 60f), Math.Abs(difference));
        }

        private static (float value, string unit) ConvertTemperature(float celsius)
        {
            GameConfig config = ModContent.GetInstance<GameConfig>();

            return config.UseFahrenheitSlider switch
            {
                1 => (celsius * 1.8f + 32f, "℉"),
                2 => (celsius + 273.15f, "K"),
                3 => ((celsius + 273.15f) * 1.8f, "°R"),
                4 => (celsius * 0.8f, "°Re"),
                5 => (celsius * 0.33f, "°N"),
                _ => (celsius, "°C")
            };
        }

        private static float CalculateFillRatio(float temperatureValue, string temperatureUnit)
        {
            return temperatureUnit switch
            {
                "℉" => MathHelper.Clamp((temperatureValue - 32f) / 90f, 0f, 1f),
                "K" => MathHelper.Clamp((temperatureValue - 273.15f) / 50f, 0f, 1f),
                _ => MathHelper.Clamp(temperatureValue / 50f, 0f, 1f)
            };
        }

        private static void DrawThermometerFill(SpriteBatch spriteBatch, Texture2D texture, Vector2 position, float fillRatio, float scale, int width, int height)
        {
            int fillHeight = (int)(texture.Height * fillRatio);
            Rectangle sourceRect = new(0, texture.Height - fillHeight, texture.Width, fillHeight);
            Vector2 fillPosition = new(position.X, position.Y + height - (int)(height * fillRatio));

            Color fillColor = GetTemperatureColor(fillRatio);
            spriteBatch.Draw(texture, fillPosition, sourceRect, fillColor, 0f, Vector2.Zero, scale, SpriteEffects.None, 0f);
        }

        private static Color GetTemperatureColor(float ratio)
        {
            ratio = MathHelper.Clamp(ratio, 0f, 1f);

            var colorStops = new (float position, Color color)[]
            {
                (0.00f, new Color(0, 100, 255)),
                (0.25f, new Color(0, 200, 255)),
                (0.50f, new Color(100, 255, 100)),
                (0.75f, new Color(255, 200, 0)),
                (1.00f, new Color(255, 50, 50))
            };

            for (int i = 0; i < colorStops.Length - 1; i++)
            {
                if (ratio >= colorStops[i].position && ratio <= colorStops[i + 1].position)
                {
                    float localRatio = (ratio - colorStops[i].position) / (colorStops[i + 1].position - colorStops[i].position);
                    return Color.Lerp(colorStops[i].color, colorStops[i + 1].color, localRatio);
                }
            }

            return colorStops[^1].color;
        }

        private static void DrawTemperatureText(SpriteBatch spriteBatch, float value, string unit, Vector2 thermometerPos, int width, int height)
        {
            string text = $"{value:F1}{unit}";
            Vector2 textSize = FontAssets.MouseText.Value.MeasureString(text);
            Vector2 textPosition = new(
                thermometerPos.X + width / 2 - textSize.X / 2 + 40,
                thermometerPos.Y + height + 5
            );
            Utils.DrawBorderString(
                spriteBatch,
                text,
                textPosition + new Vector2(2, 2),
                Color.Black,
                1f,
                0.5f,
                0f);
            Utils.DrawBorderString(
                spriteBatch,
                text,
                textPosition,
                Color.White,
                1f,
                0.5f,
                0f);
        }
    }
}